<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>part2_1_helloobject - learning-gem5</title>
        <!-- Custom HTML head -->
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../favicon.svg">
        <link rel="shortcut icon" href="../favicon.png">
        <link rel="stylesheet" href="../css/variables.css">
        <link rel="stylesheet" href="../css/general.css">
        <link rel="stylesheet" href="../css/chrome.css">
        <link rel="stylesheet" href="../css/print.css" media="print">
        <!-- Fonts -->
        <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../fonts/fonts.css">
        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../highlight.css">
        <link rel="stylesheet" href="../tomorrow-night.css">
        <link rel="stylesheet" href="../ayu-highlight.css">

        <!-- Custom theme stylesheets -->
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="../part0_introduction.html">Learning gem-5</a></li><li class="chapter-item expanded "><a href="../part0_introduction.html"><strong aria-hidden="true">1.</strong> part0_introduction</a></li><li class="chapter-item expanded "><a href="../part1/part1_1_building.html"><strong aria-hidden="true">2.</strong> part1</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../part1/part1_1_building.html"><strong aria-hidden="true">2.1.</strong> part1_1_building</a></li><li class="chapter-item expanded "><a href="../part1/part1_2_simple_config.html"><strong aria-hidden="true">2.2.</strong> part1_2_simple_config</a></li><li class="chapter-item expanded "><a href="../part1/part1_3_cache_config.html"><strong aria-hidden="true">2.3.</strong> part1_3_cache_config</a></li><li class="chapter-item expanded "><a href="../part1/part1_4_gem5_stats.html"><strong aria-hidden="true">2.4.</strong> part1_4_gem5_stats</a></li><li class="chapter-item expanded "><a href="../part1/part1_5_gem5_example_configs.html"><strong aria-hidden="true">2.5.</strong> part1_5_gem5_example_configs</a></li><li class="chapter-item expanded "><a href="../part1/part1_6_extending_configs.html"><strong aria-hidden="true">2.6.</strong> part1_6_extending_configs</a></li></ol></li><li class="chapter-item expanded "><a href="../part2/part2_0_environment.html"><strong aria-hidden="true">3.</strong> part2</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../part2/part2_0_environment.html"><strong aria-hidden="true">3.1.</strong> part2_0_environment</a></li><li class="chapter-item expanded "><a href="../part2/part2_1_helloobject.html" class="active"><strong aria-hidden="true">3.2.</strong> part2_1_helloobject</a></li><li class="chapter-item expanded "><a href="../part2/part2_2_debugging.html"><strong aria-hidden="true">3.3.</strong> part2_2_debugging</a></li><li class="chapter-item expanded "><a href="../part2/part2_3_events.html"><strong aria-hidden="true">3.4.</strong> part2_3_events</a></li><li class="chapter-item expanded "><a href="../part2/part2_4_parameters.html"><strong aria-hidden="true">3.5.</strong> part2_4_parameters</a></li><li class="chapter-item expanded "><a href="../part2/part2_5_memoryobject.html"><strong aria-hidden="true">3.6.</strong> part2_5_memoryobject</a></li><li class="chapter-item expanded "><a href="../part2/part2_6_simplecache.html"><strong aria-hidden="true">3.7.</strong> part2_6_simplecache</a></li><li class="chapter-item expanded "><a href="../part2/part2_7_arm_power_modelling.html"><strong aria-hidden="true">3.8.</strong> part2_7_arm_power_modelling</a></li><li class="chapter-item expanded "><a href="../part2/part2_8_arm_dvfs_support.html"><strong aria-hidden="true">3.9.</strong> part2_8_arm_dvfs_support</a></li></ol></li><li class="chapter-item expanded "><a href="../part3/part3_00_MSIntro.html"><strong aria-hidden="true">4.</strong> part3</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../part3/part3_00_MSIntro.html"><strong aria-hidden="true">4.1.</strong> part3_00_MSIntro</a></li><li class="chapter-item expanded "><a href="../part3/part3_01_cache-intro.html"><strong aria-hidden="true">4.2.</strong> part3_01_cache-intro</a></li><li class="chapter-item expanded "><a href="../part3/part3_02_cache-declarations.html"><strong aria-hidden="true">4.3.</strong> part3_02_cache-declarations</a></li><li class="chapter-item expanded "><a href="../part3/part3_03_cache-in-ports.html"><strong aria-hidden="true">4.4.</strong> part3_03_cache-in-ports</a></li><li class="chapter-item expanded "><a href="../part3/part3_04_cache_actions.html"><strong aria-hidden="true">4.5.</strong> part3_04_cache_actions</a></li><li class="chapter-item expanded "><a href="../part3/part3_05_cache_transitions.html"><strong aria-hidden="true">4.6.</strong> part3_05_cache_transitions</a></li><li class="chapter-item expanded "><a href="../part3/part3_06_directory.html"><strong aria-hidden="true">4.7.</strong> part3_06_directory</a></li><li class="chapter-item expanded "><a href="../part3/part3_07_MSIbuilding.html"><strong aria-hidden="true">4.8.</strong> part3_07_MSIbuilding</a></li><li class="chapter-item expanded "><a href="../part3/part3_08_configuration.html"><strong aria-hidden="true">4.9.</strong> part3_08_configuration</a></li><li class="chapter-item expanded "><a href="../part3/part3_09_running.html"><strong aria-hidden="true">4.10.</strong> part3_09_running</a></li><li class="chapter-item expanded "><a href="../part3/part3_10_MSIdebugging.html"><strong aria-hidden="true">4.11.</strong> part3_10_MSIdebugging</a></li><li class="chapter-item expanded "><a href="../part3/part3_11_simple-MI_example.html"><strong aria-hidden="true">4.12.</strong> part3_11_simple-MI_example</a></li></ol></li><li class="chapter-item expanded "><a href="../part4_gem5_101.html"><strong aria-hidden="true">5.</strong> part4_gem5_101</a></li><li class="chapter-item expanded "><a href="../http://doxygen.gem5.org/develop/index.html"><strong aria-hidden="true">6.</strong> part4_gem5_102</a></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">learning-gem5</h1>

                    <div class="right-buttons">
                        <a href="../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="创建一个非常简单的-simobject"><a class="header" href="#创建一个非常简单的-simobject">创建一个<em>非常</em>简单的 SimObject</a></h1>
<p><strong>注意</strong>：gem5 的已经有一个 名为<code>SimpleObject</code>的 SimObject子类. 实现另一个 `SimpleObject将导致二义性问题。</p>
<p>gem5 中的几乎所有对象都继承自基本 SimObject 类型。SimObjects 将主要接口导出到 gem5 中的所有对象。SimObjects 是可从<code>Python</code> 配置脚本访问的<code>C++</code>包装对象。</p>
<p>SimObjects 可以有很多参数，这些参数是通过<code>Python</code> 配置文件设置的。除了像整数和浮点数这样的简单参数外，它们还可以将其他 SimObjects 作为参数。这允许您创建复杂的系统层次结构，就像真实机器一样。</p>
<p>在本章中，我们将逐步创建一个简单的“HelloWorld” SimObject。目标是向您介绍 SimObjects 的创建方式以及所有 SimObjects 所需的样板代码。我们还将创建一个简单的<code>Python</code>配置脚本来实例化我们的 SimObject。</p>
<p>在接下来的几章中，我们将对其进行扩展，以引入<a href="https://www.gem5.org/documentation/learning_gem5/part2/debugging">调试支持</a>、<a href="https://www.gem5.org/documentation/learning_gem5/part2/events">动态事件</a>和<a href="https://www.gem5.org/documentation/learning_gem5/part2/parameters">参数</a>。</p>
<p><strong>使用 git 分支</strong></p>
<p>为每个添加到 gem5 的新功能使用一个新的 git 分支是很常见的。</p>
<p>在 gem5 中添加新功能或修改某些内容时，第一步是创建一个新分支来存储您的更改。关于 git 分支的详细信息可以在 Git 书中找到。</p>
<pre><code class="language-bash">git checkout -b hello-simobject
</code></pre>
<h2 id="第-1-步为您的新-simobject-创建一个-python-类"><a class="header" href="#第-1-步为您的新-simobject-创建一个-python-类">第 1 步：为您的新 SimObject 创建一个 Python 类</a></h2>
<p>每个 SimObject 都有一个与之关联的 Python 类。这个 Python 类描述了可以从 Python 配置文件控制的 SimObject 的参数。我们从没有参数的情况下开始配置我们的简单 SimObject。因此，我们只需要为我们的 SimObject 声明一个新类，并设置它的名称和 C++ 头文件，为 SimObject 定义 C++ 类。</p>
<p>我们可以在<code>src/learning_gem5/part2</code>创建<code>HelloObject.py</code>. 如果您已经克隆了 gem5 存储库，您将在<code>src/learning_gem5/part2</code>和<code>configs/learning_gem5/part2</code>下完成本教程中提到的文件。您可以删除这些或将它们移动到其他地方以遵循本教程。</p>
<pre><code class="language-python">from m5.params import *
from m5.SimObject import SimObject

class HelloObject(SimObject):
    type = 'HelloObject'
    cxx_header = &quot;learning_gem5/part2/hello_object.hh&quot;
</code></pre>
<p>不要求<code>type</code>与类的名称相同，但这是约定。<code>type</code>是您使用此 Python SimObject 包装的 C++ 类。只有在特殊情况下 <code>type</code>和类名才应该不同。</p>
<p><code>cxx_header</code>是包含用作类的声明文件中<code>type</code>的参数。同样，约定是使用所有小写和下划线的 SimObject 名称，但这只是约定。您可以在此处指定任何头文件。</p>
<h2 id="第-2-步在-c-中实现您的-simobject"><a class="header" href="#第-2-步在-c-中实现您的-simobject">第 2 步：在 C++ 中实现您的 SimObject</a></h2>
<p>接下来，我们需要在 <code>src/learning_gem5/part2/</code>创建<code>hello_object.hh</code>和<code>hello_object.cc</code>，以实现<code>HelloObject</code>。</p>
<p>我们将从<code>C++</code>对象的头文件开始。按照惯例，gem5 将所有头文件内容写在以文件名及其所在目录命名的<code>#ifndef/#endif</code>宏定义之间，防止循环包含。</p>
<p>我们需要在文件中做的唯一一件事就是声明我们的类。由于 <code>HelloObject</code>是 SimObject，它必须从 C++ SimObject 类继承。大多数情况下，您的 SimObject 将继承自 SimObject 的实现类，而不是 SimObject 本身。</p>
<p>SimObject 类指定了许多虚函数。但是，这些函数都不是纯虚函数，所以在最简单的情况下，除了构造函数之外，不需要实现任何函数。</p>
<p>所有 SimObjects 的构造函数都假定它将接受一个参数对象。这个参数对象是由构建系统自动创建的，并且基于SimObject的<code>Python</code>类，就像我们上面创建的那个。此参数类型的名称是<strong>根据对象名称自动生成的</strong>。对于我们的“HelloObject”，参数类型的名称是“HelloObjectParams”。</p>
<p>下面列出了我们的简单头文件所需的代码。</p>
<pre><code class="language-cpp">#ifndef __LEARNING_GEM5_HELLO_OBJECT_HH__
#define __LEARNING_GEM5_HELLO_OBJECT_HH__

#include &quot;params/HelloObject.hh&quot;
#include &quot;sim/sim_object.hh&quot;

class HelloObject : public SimObject
{
  public:
    HelloObject(const HelloObjectParams &amp;p);
};

#endif // __LEARNING_GEM5_HELLO_OBJECT_HH__
</code></pre>
<p>接下来，我们需要在<code>.cc</code>文件中实现<em>两个</em>函数。第一个是<code>HelloObject</code>的构造函数。这里我们简单地将参数对象传递给基类并打印“Hello world!”</p>
<p>通常，您<strong>永远不会</strong>在 gem5 中使用<code>std::cout</code>。相反，您应该使用调试标志。在<a href="https://www.gem5.org/documentation/learning_gem5/part2/debugging">下一章中</a>，我们将修改它以使用调试标志。但是现在，我们将简单地使用<code>std::cout</code>，因为它很简洁。</p>
<pre><code class="language-cpp">#include &quot;learning_gem5/part2/hello_object.hh&quot;

#include &lt;iostream&gt;

HelloObject::HelloObject(const HelloObjectParams &amp;params) :
    SimObject(params)
{
    std::cout &lt;&lt; &quot;Hello World! From a SimObject!&quot; &lt;&lt; std::endl;
}
</code></pre>
<p><strong>注意</strong>：您的 SimObject 的构造函数应当遵循以下签名，</p>
<pre><code class="language-cpp">Foo(const FooParams &amp;)
</code></pre>
<p>然后<code>FooParams::create()</code>被自动定义。<code>create()</code>用于调用 SimObject 构造函数并返回 SimObject 的实例。大多数 SimObject 将遵循这种模式；但是，如果您的<a href="http://doxygen.gem5.org/release/current/classSimObject.html#details">SimObject</a>不遵循此模式， <a href="http://doxygen.gem5.org/release/current/classSimObject.html#details">gem5 SimObject 文档</a> 提供了有关手动实现该<code>create()</code>方法的更多信息。</p>
<h2 id="第-3-步注册-simobject-和-c-文件"><a class="header" href="#第-3-步注册-simobject-和-c-文件">第 3 步：注册 SimObject 和 C++ 文件</a></h2>
<p>为确保<code>C++</code>代码正确编译，<code>Python</code>文件正确解析，我们需要将这些文件的信息告诉构建系统。gem5 使用 SCons 作为构建系统，因此您只需在包含 SimObject 代码的目录中创建一个 SConscript 文件。如果该目录已经有一个 SConscript 文件，只需将以下声明添加到该文件中。</p>
<p>这个文件只是一个普通的<code>Python</code>文件，所以你可以在这个文件中编写任何你想要的<code>Python</code>代码。一些脚本可能会变得非常复杂。gem5 利用这一点自动为 SimObjects 创建代码并编译为特定领域的语言，如 SLICC 和 ISA 语言。</p>
<p>在 SConscript 文件中，有许多函数在您导入后自动定义。请参阅有关该部分的内容...</p>
<p>要编译新的 SimObject，您只需在<code>src/learning_gem5/part2</code>目录中创建一个名为“SConscript”的新文件。在此文件中，您必须声明 SimObject 和<code>.cc</code>文件。下面是所需的代码。</p>
<pre><code class="language-cpp">Import('*')

SimObject('HelloObject.py')
Source('hello_object.cc')
</code></pre>
<h2 id="第-4-步重新构建-gem5"><a class="header" href="#第-4-步重新构建-gem5">第 4 步：（重新）构建 gem5</a></h2>
<p>要编译和链接您的新文件，您只需重新编译 gem5。下面的示例假设您使用的是 x86 ISA，但我们的对象中没有任何东西需要 ISA，因此，这将适用于任何 gem5 的 ISA。</p>
<pre><code class="language-bash">scons build/X86/gem5.opt
</code></pre>
<h2 id="第-5-步创建配置脚本以使用您的新-simobject"><a class="header" href="#第-5-步创建配置脚本以使用您的新-simobject">第 5 步：创建配置脚本以使用您的新 SimObject</a></h2>
<p>现在，你已经实现了SimObject，它已被编译成gem5，您需要创建或修改<code>Python</code>配置文件<code>run_hello.py</code>中 <code>configs/learning_gem5/part2</code>，以实例化对象。由于您的对象非常简单，因此不需要系统对象！除了<code>Root</code>对象之外，不需要 CPU、缓存或任何东西。所有 gem5 实例都需要一个 <code>Root</code>对象。</p>
<p>创建一个<em>非常</em>简单的配置脚本，首先，导入 m5 和您编译的所有对象。</p>
<pre><code class="language-python">import m5
from m5.objects import *
</code></pre>
<p>接下来，根据所有 gem5 实例的要求，您必须实例化<code>Root</code>对象。</p>
<pre><code class="language-python">root = Root(full_system = False)
</code></pre>
<p>现在，您可以实例化您的<code>HelloObject</code>。您需要做的就是调用<code>Python</code>“构造函数”。稍后，我们将看看如何通过<code>Python</code>构造函数指定参数。除了实例化对象之外，您还需要确保它是Root的成员变量。只有作为<code>Root</code>成员的 SimObjects 才会在<code>C++</code>中实例化.</p>
<pre><code class="language-python">root.hello = HelloObject()
</code></pre>
<p>最后，你需要调用<code>m5</code>上的<code>instantiate</code>模块运行模拟！</p>
<pre><code class="language-python">m5.instantiate()

print(&quot;Beginning simulation!&quot;)
exit_event = m5.simulate()
print('Exiting @ tick {} because {}'
      .format(m5.curTick(), exit_event.getCause()))
</code></pre>
<p>修改src/目录下的文件后记得重建gem5。运行配置文件的命令行在“command line:”后面的输出中。输出应如下所示：</p>
<p>注意：如果后续“向 SimObjects 和更多事件添加参数”章节的代码 (goodbye_object) 在您的<code>src/learning_gem5/part2</code> 目录中，run_hello.py 将报错。如果您删除这些文件或将它们移到 gem5 目录之外，<code>run_hello.py</code>则应提供以下输出。</p>
<pre><code class="language-bash">    gem5 Simulator System.  http://gem5.org
    gem5 is copyrighted software; use the --copyright option for details.

    gem5 compiled May  4 2016 11:37:41
    gem5 started May  4 2016 11:44:28
    gem5 executing on mustardseed.cs.wisc.edu, pid 22480
    command line: build/X86/gem5.opt configs/learning_gem5/part2/run_hello.py

    Global frequency set at 1000000000000 ticks per second
    Hello World! From a SimObject!
    Beginning simulation!
    info: Entering event queue @ 0.  Starting simulation...
    Exiting @ tick 18446744073709551615 because simulate() limit reached
</code></pre>
<p>恭喜！您已经编写了您的第一个 SimObject。在接下来的章节中，我们将扩展这个 SimObject 并探索您可以使用 SimObjects 做什么。</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../part2/part2_0_environment.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                            <a rel="next" href="../part2/part2_2_debugging.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../part2/part2_0_environment.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                    <a rel="next" href="../part2/part2_2_debugging.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>

        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
        <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
    </body>
</html>
